package ai

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"gitee.com/li-zhenyi/yi-nian-zhi-jian/backend/internal/model"
)

// AIClient AI客户端接口
// 定义与AI服务交互的方法
type AIClient interface {
	// 生成历练故事
	GenerateAdventure(ctx *model.AdventureContext) (*model.AdventureStory, error)
	// 计算选择结果
		CalculateResult(ctx *model.AdventureContext, choice *model.AdventureChoice, conversationID string) (*model.AdventureResult, error)
}

// CozeClient Coze AI客户端实现
type CozeClient struct {
	apiKey  string
	botID   string
	baseURL string
	client  *http.Client
}

// NewCozeClient 创建Coze客户端
func NewCozeClient(apiKey, botID string) AIClient {
	return &CozeClient{
		apiKey:  apiKey,
		botID:   botID,
		baseURL: "https://api.coze.cn/v1",
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// CozeRequest Coze API请求结构
type CozeRequest struct {
	BotID       string                 `json:"bot_id"`
	UserID      string                 `json:"user_id"`
	Stream      bool                   `json:"stream"`
	Query       string                 `json:"query"`
	ChatHistory []CozeChatMessage      `json:"chat_history,omitempty"`
	CustomVars  map[string]interface{} `json:"custom_variables,omitempty"`
}

// CozeChatMessage Coze对话消息
type CozeChatMessage struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

// CozeResponse Coze API响应结构
type CozeResponse struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    struct {
		ConversationID string `json:"conversation_id"`
		Messages       []struct {
			Role    string `json:"role"`
			Content string `json:"content"`
			Type    string `json:"type"`
		} `json:"messages"`
	} `json:"data"`
}

// GenerateAdventure 生成历练故事
func (c *CozeClient) GenerateAdventure(ctx *model.AdventureContext) (*model.AdventureStory, error) {
	// 构建提示词
	prompt := c.buildAdventurePrompt(ctx)

	// 调用Coze API
	response, err := c.callCozeAPI(ctx.UserID, prompt, nil)
	if err != nil {
		return nil, fmt.Errorf("调用Coze API失败: %w", err)
	}

	// 解析响应
	story, err := c.parseAdventureResponse(response)
	if err != nil {
		return nil, fmt.Errorf("解析AI响应失败: %w", err)
	}

	return story, nil
}

// CalculateResult 计算选择结果
func (c *CozeClient) CalculateResult(ctx *model.AdventureContext, choice *model.AdventureChoice, conversationID string) (*model.AdventureResult, error) {
	// 构建结果计算提示词
	prompt := c.buildResultPrompt(ctx, choice)

	// 调用Coze API
	// 传递 conversationID 给 Coze API
	response, err := c.callCozeAPIWithConversationID(ctx.UserID, prompt, nil, conversationID)
	if err != nil {
		return nil, fmt.Errorf("调用Coze API失败: %w", err)
	}

	// 解析结果
	result, err := c.parseResultResponse(response)
	if err != nil {
		return nil, fmt.Errorf("解析结果失败: %w", err)
	}

	return result, nil
}

// buildAdventurePrompt 构建历练生成提示词
func (c *CozeClient) buildAdventurePrompt(ctx *model.AdventureContext) string {
	return fmt.Sprintf(`你是一个专业的修仙小说作家，擅长创作生动的修仙奇遇故事。

用户信息：
- 境界：%s %d层
- 根骨：%d
- 悟性：%d
- 运气：%d
- 历练次数：%d

任务：
1. 根据用户当前境界，生成一个适合的修仙奇遇故事
2. 故事要包含修仙元素（灵气、法宝、丹药、妖兽等）
3. 提供2-3个决策选项，每个选项有不同的风险和收益
4. 高运气的用户更容易遇到好事，低运气容易遇到危险
5. 保持世界观一致性，符合传统修仙设定
6. 故事长度控制在100-200字

输出格式：严格按照JSON格式输出，不要有任何额外文字
{
  "adventure_id": "生成唯一ID",
  "story": {
    "title": "奇遇标题（10字内）",
    "content": "详细的故事描述（100-200字）",
    "scene": "场景类型（如：深山、洞府、集市等）",
    "mood": "氛围（神秘/危险/平和/紧张）"
  },
  "choices": [
    {
      "id": 1,
      "text": "选择描述（20字内）",
      "risk_level": "low/medium/high",
      "success_rate": 80,
      "possible_rewards": ["奖励描述1", "奖励描述2"]
    },
    {
      "id": 2,
      "text": "选择描述",
      "risk_level": "medium",
      "success_rate": 60,
      "possible_rewards": ["奖励描述"]
    }
  ]
}`,
		ctx.Realm, ctx.RealmLevel, ctx.Talent, ctx.Comprehension, ctx.Luck, ctx.AdventureCount)
}

// buildResultPrompt 构建结果计算提示词
func (c *CozeClient) buildResultPrompt(ctx *model.AdventureContext, choice *model.AdventureChoice) string {
	return fmt.Sprintf(`基于用户的选择，计算历练结果。

用户信息：
- 境界：%s %d层
- 运气：%d

用户选择：
- 选项：%s
- 风险等级：%s
- 成功率：%d%%

任务：
1. 根据成功率和用户运气，判断是否成功
2. 计算具体奖励（修为、灵石、物品）
3. 生成结果描述
4. 如果失败，描述后果

输出格式：严格按照JSON格式输出
{
  "success": true,
  "description": "结果描述（50-100字）",
  "reward": {
    "cultivation": 150,
    "spirit_stones": 50,
    "items": [
      {"item_id": 6, "item_name": "培元丹", "quantity": 2}
    ],
    "experience": "经验描述"
  },
  "consequence": "如果有负面后果，在此描述",
  "next_hint": "给玩家的下次提示"
}`,
		ctx.Realm, ctx.RealmLevel, ctx.Luck,
		choice.Text, choice.RiskLevel, choice.SuccessRate)
}

// callCozeAPI 调用Coze API
func (c *CozeClient) callCozeAPI(userID int64, query string, history []CozeChatMessage) (*CozeResponse, error) {
	// 构建请求
	reqBody := CozeRequest{
		BotID:       c.botID,
		UserID:      fmt.Sprintf("%d", userID),
		Stream:      false,
		Query:       query,
		ChatHistory: history,
	}

	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, err
	}

	// 创建HTTP请求
	req, err := http.NewRequest("POST", c.baseURL+"/chat", bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, err
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+c.apiKey)

	// 发送请求
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// 解析响应
	var cozeResp CozeResponse
	if err := json.Unmarshal(body, &cozeResp); err != nil {
		return nil, err
	}

	if cozeResp.Code != 0 {
		return nil, fmt.Errorf("Coze API错误: %s", cozeResp.Message)
	}

	return &cozeResp, nil
}

// parseAdventureResponse 解析历练故事响应
func (c *CozeClient) parseAdventureResponse(response *CozeResponse) (*model.AdventureStory, error) {
	// 提取AI返回的内容
	if len(response.Data.Messages) == 0 {
		return nil, errors.New("AI响应为空")
	}

	var content string
	for _, msg := range response.Data.Messages {
		if msg.Role == "assistant" && msg.Type == "answer" {
			content = msg.Content
			break
		}
	}

	if content == "" {
		return nil, errors.New("未找到AI回答")
	}

	// 解析JSON
	var story model.AdventureStory
	if err := json.Unmarshal([]byte(content), &story); err != nil {
		// 如果JSON解析失败，尝试提取JSON部分
		content = extractJSON(content)
		if err := json.Unmarshal([]byte(content), &story); err != nil {
			return nil, fmt.Errorf("解析AI响应JSON失败: %w", err)
		}
	}

	return &story, nil
}

// parseResultResponse 解析结果响应
func (c *CozeClient) parseResultResponse(response *CozeResponse) (*model.AdventureResult, error) {
	// 提取AI返回的内容
	if len(response.Data.Messages) == 0 {
		return nil, errors.New("AI响应为空")
	}

	var content string
	for _, msg := range response.Data.Messages {
		if msg.Role == "assistant" && msg.Type == "answer" {
			content = msg.Content
			break
		}
	}

	if content == "" {
		return nil, errors.New("未找到AI回答")
	}

	// 解析JSON
	var result model.AdventureResult
	if err := json.Unmarshal([]byte(content), &result); err != nil {
		// 如果JSON解析失败，尝试提取JSON部分
		content = extractJSON(content)
		if err := json.Unmarshal([]byte(content), &result); err != nil {
			return nil, fmt.Errorf("解析结果JSON失败: %w", err)
		}
	}

	return &result, nil
}

// extractJSON 从文本中提取JSON部分
// AI有时会在JSON前后添加说明文字，需要提取纯JSON
func extractJSON(text string) string {
	// 查找第一个 { 和最后一个 }
	start := -1
	end := -1
	
	for i, ch := range text {
		if ch == '{' && start == -1 {
			start = i
		}
		if ch == '}' {
			end = i + 1
		}
	}
	
	if start >= 0 && end > start {
		return text[start:end]
	}
	
	return text
}

// MockAIClient 模拟AI客户端（用于开发测试）
type MockAIClient struct{}

// NewMockAIClient 创建模拟AI客户端
func NewMockAIClient() AIClient {
	return &MockAIClient{}
}

// GenerateAdventure 生成模拟历练故事
func (m *MockAIClient) GenerateAdventure(ctx *model.AdventureContext) (*model.AdventureStory, error) {
	// 返回预定义的模拟数据
	return &model.AdventureStory{
		AdventureID: "mock-001",
		Story: model.AdventureStoryData{
			Title:   "神秘洞府",
			Content: fmt.Sprintf("你在%s的深山中探索时，发现了一处隐蔽的洞府。洞府门口刻着古老的符文，散发着淡淡的灵气。洞府深处传来阵阵宝光，似乎藏有珍宝。但同时，你也感受到一丝危险的气息...", ctx.Realm),
			Scene:   "深山洞府",
			Mood:    "神秘",
		},
		Choices: []model.AdventureChoice{
			{
				ID:          1,
				Text:        "小心翼翼地探索洞府",
				RiskLevel:   "low",
				SuccessRate: 80,
				PossibleRewards: []string{"修为+100", "可能获得丹药"},
			},
			{
				ID:          2,
				Text:        "直接冲向宝光闪烁处",
				RiskLevel:   "high",
				SuccessRate: 50,
				PossibleRewards: []string{"法宝", "大量修为", "或触发机关受伤"},
			},
			{
				ID:          3,
				Text:        "在洞府外打坐修炼，吸收灵气",
				RiskLevel:   "low",
				SuccessRate: 90,
				PossibleRewards: []string{"修为+50", "稳健提升"},
			},
		},
		Context: *ctx,
	}, nil
}

// CalculateResult 计算模拟结果
func (m *MockAIClient) CalculateResult(ctx *model.AdventureContext, choice *model.AdventureChoice, conversationID string) (*model.AdventureResult, error) {
	// 简单模拟结果计算
	success := choice.SuccessRate > 50 || ctx.Luck > 12
	
	if success {
		return &model.AdventureResult{
			Success:     true,
			Description: fmt.Sprintf("你的选择很明智！在%s的加持下，你成功获得了宝物。", ctx.Realm),
			Reward: model.AdventureReward{
				Cultivation:  150,
				SpiritStones: 100,
				Items: []model.AdventureRewardItem{
					{ItemID: 6, ItemName: "培元丹", Quantity: 2},
				},
				Experience: "这次历练让你对修仙之道有了更深的理解。",
			},
			Consequence: "",
			NextHint:    "继续努力修炼，更多奇遇等待着你！",
		}, nil
	}
	
	return &model.AdventureResult{
		Success:     false,
		Description: "虽然这次没有获得预期的收获，但经验也是宝贵的财富。",
		Reward: model.AdventureReward{
			Cultivation:  50,
			SpiritStones: 20,
			Items:        []model.AdventureRewardItem{},
			Experience:   "失败是成功之母，你从中学到了教训。",
		},
		Consequence: "损失了一些体力，但没有受重伤。",
		NextHint:    "提升实力后再来挑战吧！",
	}, nil
}

// callCozeAPIWithConversationID 调用Coze API（带会话ID）
func (c *CozeClient) callCozeAPIWithConversationID(userID int64, query string, history []CozeChatMessage, conversationID string) (*CozeResponse, error) {
	reqBody := CozeRequest{
		BotID:       c.botID,
		UserID:      fmt.Sprintf("%d", userID),
		Stream:      false,
		Query:       query,
		ChatHistory: history,
	}
	
	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, err
	}
	
	// 创建HTTP请求，带conversation_id参数
	url := c.baseURL + "/chat?conversation_id=" + conversationID
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, err
	}
	
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+c.apiKey)
	
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	
	var cozeResp CozeResponse
	if err := json.Unmarshal(body, &cozeResp); err != nil {
		return nil, err
	}
	
	if cozeResp.Code != 0 {
		return nil, fmt.Errorf("Coze API错误: %s", cozeResp.Message)
	}
	
	return &cozeResp, nil
}
